#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

////////////////////// WIFI 配置
#define ssid "PUMPU"              // 定义Wi-Fi的SSID（网络名称）
#define password "1234567890abc"  // 定义Wi-Fi的密码
// 设置要创建的热点名与密码
const char * apssid = "BK7238-AP";
const char * appassword = "12345678";
////////////////////// MQTT 配置
#define mqttServer "192.168.0.118"  // 定义MQTT服务器的IP地址
#define mqttPort 1883               // 定义MQTT服务器的端口号，默认端口为1883
#define user "BK7238"               // 定义MQTT用户名
#define pass "BK7238"               // 定义MQTT密码

String clientId = "BK7238";                      // 定义MQTT客户端ID
String pubTopic = "v1/devices/me/rpc/response";  // 定义MQTT发布主题
#define subTopic "v1/devices/me/rpc/request/+"   // 定义MQTT订阅主题，使用通配符“+”

WiFiClient espClient;            // 定义WiFi客户端，用于与WiFi网络通信
PubSubClient client(espClient);  // 定义MQTT客户端，用于与MQTT服务器通信

// 声明标志位
bool gpio28State ;  // 定义GPIO 28引脚的状态变量

// setup 函数，初始化系统和设置硬件
void setup() {
  Serial.begin(115200);           // 初始化串口通信，波特率设置为115200
  pinMode(28, OUTPUT);            // 设置GPIO 28为输出模式
  digitalWrite(28, gpio28State);  // 将GPIO 28的初始状态设置为LOW
  
  // 创建热点
  WiFi.softAP(apssid, appassword);
  //  打印热点 IP
  Serial.print("Wi-Fi 接入的 IP：");
  Serial.println(WiFi.softAPIP());

  WiFi.begin(ssid, password);  // 开始连接Wi-Fi

  // 等待Wi-Fi连接成功
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);         // 每隔100毫秒检查一次Wi-Fi状态
    Serial.print('.');  // 未连接时输出点表示等待
  }
  Serial.println("WIFI CONNECT OK");  // Wi-Fi连接成功，输出提示信息
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(mqttServer, mqttPort);  // 设置MQTT服务器的IP地址和端口号
  client.setCallback(mqttCallback);        // 设置MQTT消息回调函数
}

// loop 函数，主循环程序
void loop() {
  // 如果MQTT客户端未连接，则尝试重新连接
  if (!client.connected()) {
    client.connect(clientId.c_str(), user, pass);  // 连接到MQTT服务器，使用客户端ID和用户名密码
    client.subscribe(subTopic);                    // 订阅MQTT主题
    Serial.println("MQTT CONNECT OK");             // 输出MQTT连接成功的提示
  }
  client.loop();  // 保持MQTT连接并处理MQTT通信
}

// 读取串口数据并通过MQTT发布消息
void usartRead() {
  if (Serial.available() <= 0)  // 检查串口中是否有数据
    return;                     // 如果没有数据则返回
  if (Serial.read() != '{')     // 检查是否有以 "{" 开头的数据
    return;

  delay(5);  // 等待5毫秒确保数据完整

  char text[100];                   // 定义存储数据的字符数组
  int len = 1;                      // 初始化字符数组的长度
  while (Serial.available() > 0) {  // 循环读取串口数据
    text[len++] = Serial.read();    // 将数据存储到数组中
  }
  text[0] = '{';  // 手动设置第一个字符为 "{"
  text[len] = 0;  // 将字符数组末尾设置为字符串结束符

  client.publish(pubTopic.c_str(), text);  // 通过MQTT发布读取到的数据
}

// MQTT消息回调函数
void mqttCallback(char *topic, byte *payload, unsigned int length) {
  char *ret = strrchr(topic, '/');  // 从主题中查找最后一个“/”的位置
  if (ret == NULL)                  // 如果没有找到，则返回
    return;

  String pubTopicTemp = pubTopic + ret;  // 拼接新的发布主题

  // 创建一个JSON文档用于存储解析后的MQTT消息
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, payload, length);  // 反序列化JSON数据
  if (error) {                                                         // 如果反序列化失败
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.c_str());  // 输出错误信息
    return;
  }

  const char *method = doc["method"];  // 从JSON消息中提取 "method" 字段
  if (method == NULL) {                // 如果method字段为空则返回
    return;
  }

  // 根据 "method" 字段来设置或获取 GPIO 28 的状态
  if (strcmp(method, "setValue") == 0) {
    gpio28State = doc["params"];  // 更新标志位，设置GPIO 28的状态
    Serial.println("Setting GPIO 28 to: " + String(gpio28State));
    digitalWrite(28, gpio28State ? HIGH : LOW);  // 根据标志位的值设置GPIO 28的状态
  } else if (strcmp(method, "getValue") == 0) {
    // 如果method为"getValue"，则返回当前GPIO 28的状态
    if (gpio28State) {
      Serial.println("Publishing: true");
      client.publish(pubTopicTemp.c_str(), "true");  // 通过MQTT发布状态为true
    } else {
      Serial.println("Publishing: false");
      client.publish(pubTopicTemp.c_str(), "false");  // 通过MQTT发布状态为false
    }
  }
}
